﻿
-----------------------------------------------------------------------
-- MatrixOption.lua
--
-- A Framework for World Of Warcraft addons
-- Copyright (C) 2007  wwkkii
-- 
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- any later version.
-- 
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.
-- 
-- You should have received a copy of the GNU General Public License
-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
-- 
-- Home Page: http://code.google.com/p/wowmatrix
-----------------------------------------------------------------------

local __version__ = { "MatrixOption", 0, 1, 1 };
if (MatrixUpdateVersion(__version__)) then return; end

MATRIX_OPTION_BAD_VALUE = { };

-----------------------------------------------------------------------
-- Local function
-----------------------------------------------------------------------

local function Matrix_IsItemName(name)
	return (string.match(name, "([a-z][a-zA-Z0-9_]*)") == name);
end

-----------------------------------------------------------------------
-- MatrixOption Class
-----------------------------------------------------------------------

MatrixClass("MatrixOption", MatrixObject, MATRIX_VIRTUAL_CLASS);

function MatrixOption:Initial(name, defval)
	if (not Matrix_IsItemName(name)) then
		matrix.Crash("ERROR_BAD_NAME", "Option", name);
	end
	self.__name__ = name;
	self.__default__ = defval;
end

function MatrixOption:Final()
	self.__owner__ = nil;
	self.__value__ = nil;
	self.__default__ = nil;
end

function MatrixOption:Value()
	return self.__value__;
end

function MatrixOption:Change(newval)
	local raw;

	if (self.__value__ == newval) then
		return;
	end
	newval = self:Check(newval);
	if (newval == MATRIX_OPTION_BAD_VALUE) then
		self:Crash("ERROR_BAD_OPTION_VALUE", newval);
	end
	raw = self.__value__;
	self.__value__ = val;
end

function MatrixOption:Reset()
	self:Change(self.__default__);
end

function MatrixOption:Check(val)
	return val;
end

function MatrixOption:Dump(nest)
	local prefix;

	if (not nest) then
		prefix = "";
	else
		prefix = string.rep("  ", nest);
	end
	matrix.Print(prefix, self:Name(), " = ", self:Value());
end

-----------------------------------------------------------------------
-- MatrixNullOption Class
-----------------------------------------------------------------------

MatrixClass("MatrixNullOption", MatrixOption);

function MatrixNullOption:Initial(name, ...)
	self:Super(name, nil);
	self.__items__ = { ... };
end

function MatrixNullOption:Change(val)
	for idx = 1, #self.__items__, 1 do
		if (self.__items__[idx] == val) then
		end
	end
end

-----------------------------------------------------------------------
-- MatrixBoolOption Class
-----------------------------------------------------------------------

MatrixClass("MatrixBoolOption", MatrixOption);

function MatrixBoolOption:Check(val)
	if (val) then
		return true;
	else
		return false;
	end
end

-----------------------------------------------------------------------
-- MatrixNumOption Class
-----------------------------------------------------------------------

MatrixClass("MatrixNumOption", MatrixOption);

function MatrixNumOption:Check(val)
	if (type(val) == "number") then
		return val;
	end
	if (val == nil) then
		return 0;
	end
	return MATRIX_OPTION_BAD_VALUE;
end

-----------------------------------------------------------------------
-- MatrixRangeOption Class
-----------------------------------------------------------------------

MatrixClass("MatrixRangeOption", MatrixNumOption);

function MatrixRangeOption:Initial(name, defval, minv, maxv, step)
	self:Super(name, defval);
	if (type(minv) ~= "number") then
		minv = 0;
	end
	if (type(maxv) ~= "number") then
		maxv = minv + 100;
	end
	if (type(step) ~= "number") then
		step = (maxv - minv) / 100;
	end
	self.__minimize__ = minv;
	self.__maximize__ = maxv;
	self.__step__ = step;
end

function MatrixRangeOption:Check(val)
	if (type(val) ~= "number") then
		return MATRIX_OPTION_BAD_VALUE;
	elseif (val < self.__minimize__) then
		return self.__minimize__;
	elseif (val > self.__maximize__) then
		return self.__maximize__;
	else
		return val;
	end
end

-----------------------------------------------------------------------
-- MatrixStrOption Class
-----------------------------------------------------------------------

MatrixClass("MatrixStrOption", MatrixOption);

function MatrixStrOption:Check(val)
	if (val == nil) then
		return "";
	end
	return tostring(val);
end

-----------------------------------------------------------------------
-- MatrixDirOption Class
-----------------------------------------------------------------------

MatrixClass("MatrixDirOption", MatrixOption);

function MatrixDirOption:Initial(name, ...)
	local idx;

	self:Super(name, nil);
	self.__items__ = { ... };
	for idx = 1, #self.__items__, 1 do
		local node = self.__items__[idx];
		if (not node:Match(MatrixOption)) then
			self:Crash("ERROR_BAD_OPTION", name);
		end
		if (self[node:Name()]) then
			self:Crash("ERROR_NAME_CONFLICT", "Option", node:Name());
		end
		self[node:Name()] = node;
	end
end

function MatrixDirOption:Final()
	local idx;

	for idx = 1, #self.__items__, 1 do
		local node = self.__items__[idx];
		if (matrix.IsObject(node) and (self[node:Name()] == node)) then
			self[node:Name()] = nil;
		end
	end
	self.__items__ = nil;
end

function MatrixDirOption:Change(newval)
	local idx;

	if (self.__value__ == newval) then
		return;
	end
	if (type(newval) ~= "table") then
		self.__value__ = { };
	else
		self.__value__ = newval;
	end
	for idx = 1, #self.__items__, 1 do
		local node = self.__items__[idx];
		if (newval[node:Name()]) then
			node:Change(newval[node:Name()]);
		else
			node:Reset();
		end
		self.__value__[node:Name()] = node:Value();
	end
end

function MatrixDirOption:Reset()
	local idx;
	self.__value__ = { }
	for idx = 1, #self.__items__, 1 do
		local node = self.__items__[idx];
		node:Reset();
		self.__value__[node:Name()] = node:Value();
	end
end

function MatrixDirOption:Dump(nest)
	local prefix, idx;

	if (not nest) then
		prefix = "";
		nest = 0;
	else
		prefix = string.rep("  ", nest);
	end
	matrix.Print(prefix, self:Name(), ":");
	for idx = 1, #self.__items__, 1 do
		self.__items__[idx]:Dump(nest + 1);
	end
end

function MatrixDirOption:GetItem(idx)
	if (self.__items__) then
		return self.__items__[idx];
	end
	return nil;
end

function MatrixDirOption:GetCount()
	if (self.__items__) then
		return #self.__items__;
	end
	return 0;
end

-----------------------------------------------------------------------
-- MatrixItemOption Class
-----------------------------------------------------------------------

MatrixClass("MatrixItemOption", MatrixBoolOption, MATRIX_FINAL_CLASS);

function MatrixItemOption:Initial(parent, name, defval)
	self:Super(name, defval);
	self.__parent__ = parent;
end

-----------------------------------------------------------------------
-- MatrixToggleOption Class
-----------------------------------------------------------------------

MatrixClass("MatrixToggleOption", MatrixDirOption);

function MatrixToggleOption:Initial(name, defval, ...)
	local idx, items, arglist;

	arglist = { ... };
	items = { };
	for idx = 1, #arglist, 1 do
		items[#items + 1] = MatrixItemOption(self, arglist[idx], defval);
	end
	self:Super(name, unpack(items));
	self.__style__ = 0;
end

-----------------------------------------------------------------------
-- MatrixChoiceOption Class
-----------------------------------------------------------------------

MatrixClass("MatrixChoiceOption", MatrixDirOption);

function MatrixChoiceOption:Initial(name, defval, ...)
	local idx, items, arglist;

	arglist = { ... };
	items = { };
	for idx = 1, #arglist, 1 do
		items[#items + 1] = MatrixItemOption(self, arglist[idx], defval);
	end
	self:Super(name, unpack(items));
	self.__style__ = 1;
end

function MatrixChoiceOption:Reset()
	self:Change(self.__default__);
end

function MatrixChoiceOption:GetCursel()
end

-----------------------------------------------------------------------
-- MatrixListOption Class
-----------------------------------------------------------------------

MatrixClass("MatrixListOption", MatrixDirOption);

function MatrixListOption:Initial(name, style)
	self:Super(name);
	self.__style__ = style;
end

function MatrixListOption:GetCursel()
end

function MatrixListOption:Add(item)
end

function MatrixListOption:Remove(item)
end

function MatrixListOption:Move(pos, cmd)
end
